import datetime
import os
import tkinter as tk
from tkinter import filedialog, messagebox

import ttkbootstrap as ttkb
from PIL import Image, ImageTk, ImageEnhance, ImageDraw
from ttkbootstrap.constants import *

from app.util.annotation_util import annotate, ClassInfo
from app.view.base_view import View


@annotate(ClassInfo(name="ImgEdit", category="tool"))
class ImgEditView(View):
    def __init__(self, parent, controller):
        super().__init__(parent, controller)
        # 初始化变量
        self.image_path = None
        self.original_image = None
        self.edited_image = None
        self.displayed_image = None
        self.scale_factor = 1.0
        self.drawing_tool = None  # 当前绘图工具
        self.start_x = None
        self.start_y = None
        self.temp_drawing = None
        self.drawing_color = "red"
        self.line_width = 2

        # 创建界面
        self._create_widgets()

    def _create_widgets(self):
        # 顶部工具栏 - 文件操作
        top_frame = ttkb.Frame(self, padding=10)
        top_frame.pack(fill=X)

        ttkb.Button(top_frame, text="打开图片", command=self.open_image, bootstyle=PRIMARY).pack(side=LEFT, padx=5)
        ttkb.Button(top_frame, text="保存图片", command=self.save_image, bootstyle=SUCCESS).pack(side=LEFT, padx=5)
        ttkb.Button(top_frame, text="另存为", command=self.save_image_as, bootstyle=INFO).pack(side=LEFT, padx=5)
        ttkb.Button(top_frame, text="重置", command=self.reset_image, bootstyle=WARNING).pack(side=LEFT, padx=5)

        # 主内容区域
        main_frame = ttkb.Frame(self)
        main_frame.pack(fill=BOTH, expand=True, padx=10, pady=5)

        # 左侧工具面板
        left_panel = ttkb.LabelFrame(main_frame, text="编辑工具", padding=10)
        left_panel.pack(side=LEFT, fill=Y, padx=(0, 10))

        # 缩放工具
        ttkb.Label(left_panel, text="缩放控制:").pack(anchor=W, pady=5)
        zoom_frame = ttkb.Frame(left_panel)
        zoom_frame.pack(fill=X, pady=5)
        ttkb.Button(zoom_frame, text="放大", command=lambda: self.zoom_image(1.2), bootstyle=OUTLINE).pack(side=LEFT,
                                                                                                           padx=2,
                                                                                                           fill=X,
                                                                                                           expand=True)
        ttkb.Button(zoom_frame, text="缩小", command=lambda: self.zoom_image(0.8), bootstyle=OUTLINE).pack(side=LEFT,
                                                                                                           padx=2,
                                                                                                           fill=X,
                                                                                                           expand=True)

        # 绘图工具
        ttkb.Label(left_panel, text="绘图工具:").pack(anchor=W, pady=5)
        draw_frame = ttkb.Frame(left_panel)
        draw_frame.pack(fill=X, pady=5)

        tools = [
            ("选择", None),
            ("直线", "line"),
            ("矩形", "rectangle"),
            ("圆形", "oval"),
            ("三角形", "triangle")
        ]

        for text, tool in tools:
            ttkb.Button(
                draw_frame,
                text=text,
                command=lambda t=tool: self.set_drawing_tool(t),
                bootstyle=OUTLINE
            ).pack(side=TOP, pady=2, fill=X)

        # 线条颜色选择
        ttkb.Label(left_panel, text="线条颜色:").pack(anchor=W, pady=5)
        color_frame = ttkb.Frame(left_panel)
        color_frame.pack(fill=X, pady=5)

        colors = ["red", "blue", "green", "black", "yellow", "purple"]
        for color in colors:
            btn = ttkb.Button(
                color_frame,
                text="",
                width=2,
                command=lambda c=color: self.set_drawing_color(c),
                bootstyle=OUTLINE
            )
            btn.pack(side=LEFT, padx=1, fill=X, expand=True)
            btn.configure(style=f"{color}.TButton")

        # 线条宽度
        ttkb.Label(left_panel, text="线条宽度:").pack(anchor=W, pady=5)
        self.width_scale = ttkb.Scale(left_panel, from_=1, to=10, value=2, orient=HORIZONTAL,
                                      command=self.set_line_width)
        self.width_scale.pack(fill=X, pady=5)

        # 裁剪按钮
        ttkb.Button(left_panel, text="裁剪", command=self.crop_image, bootstyle=DANGER).pack(fill=X, pady=10)

        # 右侧参数调整面板
        right_panel = ttkb.LabelFrame(main_frame, text="图片调整", padding=10)
        right_panel.pack(side=RIGHT, fill=Y, padx=(10, 0))

        # 曝光调整
        ttkb.Label(right_panel, text="曝光:").pack(anchor=W, pady=5)
        self.exposure_scale = ttkb.Scale(right_panel, from_=0.1, to=3.0, value=1.0, orient=HORIZONTAL,
                                         command=self.adjust_exposure)
        self.exposure_scale.pack(fill=X, pady=5)
        self.exposure_label = ttkb.Label(right_panel, text="1.00")
        self.exposure_label.pack(anchor=W)

        # 透明度调整
        ttkb.Label(right_panel, text="透明度:").pack(anchor=W, pady=5)
        self.alpha_scale = ttkb.Scale(right_panel, from_=0.1, to=1.0, value=1.0, orient=HORIZONTAL,
                                      command=self.adjust_alpha)
        self.alpha_scale.pack(fill=X, pady=5)
        self.alpha_label = ttkb.Label(right_panel, text="1.00")
        self.alpha_label.pack(anchor=W)

        # 对比度调整
        ttkb.Label(right_panel, text="对比度:").pack(anchor=W, pady=5)
        self.contrast_scale = ttkb.Scale(right_panel, from_=0.1, to=3.0, value=1.0, orient=HORIZONTAL,
                                         command=self.adjust_contrast)
        self.contrast_scale.pack(fill=X, pady=5)
        self.contrast_label = ttkb.Label(right_panel, text="1.00")
        self.contrast_label.pack(anchor=W)

        # 饱和度调整
        ttkb.Label(right_panel, text="饱和度:").pack(anchor=W, pady=5)
        self.saturation_scale = ttkb.Scale(right_panel, from_=0.0, to=2.0, value=1.0, orient=HORIZONTAL,
                                           command=self.adjust_saturation)
        self.saturation_scale.pack(fill=X, pady=5)
        self.saturation_label = ttkb.Label(right_panel, text="1.00")
        self.saturation_label.pack(anchor=W)

        # 图片显示区域
        self.image_frame = ttkb.LabelFrame(main_frame, text="图片预览", padding=10)
        self.image_frame.pack(side=LEFT, fill=BOTH, expand=True)

        # 添加滚动条
        canvas_frame = ttkb.Frame(self.image_frame)
        canvas_frame.pack(fill=BOTH, expand=True)

        scroll_x = ttkb.Scrollbar(canvas_frame, orient=HORIZONTAL)
        scroll_x.pack(side=BOTTOM, fill=X)

        scroll_y = ttkb.Scrollbar(canvas_frame, orient=VERTICAL)
        scroll_y.pack(side=RIGHT, fill=Y)

        self.canvas = ttkb.Canvas(canvas_frame, bg="white", xscrollcommand=scroll_x.set, yscrollcommand=scroll_y.set)
        self.canvas.pack(fill=BOTH, expand=True)

        scroll_x.config(command=self.canvas.xview)
        scroll_y.config(command=self.canvas.yview)

        # 绑定鼠标事件用于绘图
        self.canvas.bind("<ButtonPress-1>", self.on_mouse_down)
        self.canvas.bind("<B1-Motion>", self.on_mouse_drag)
        self.canvas.bind("<ButtonRelease-1>", self.on_mouse_up)

        # 底部日志区域
        log_frame = ttkb.LabelFrame(self, text="操作日志", padding=10)
        log_frame.pack(fill=BOTH, expand=True, padx=10, pady=5)

        self.log_text = ttkb.Text(log_frame, height=5, state=DISABLED)
        self.log_text.pack(side=LEFT, fill=BOTH, expand=True)

        scrollbar = ttkb.Scrollbar(log_frame, command=self.log_text.yview)
        scrollbar.pack(side=RIGHT, fill=Y)
        self.log_text.config(yscrollcommand=scrollbar.set)

        # 添加初始日志
        self.add_log("应用程序启动成功")

    def open_image(self):
        """打开图片文件"""
        file_path = filedialog.askopenfilename(
            filetypes=[
                ("图片文件", "*.png;*.jpg;*.jpeg;*.ico;*.bmp"),
                ("所有文件", "*.*")
            ]
        )

        if file_path:
            try:
                self.image_path = file_path
                self.original_image = Image.open(file_path)
                # 确保图片有alpha通道以便处理透明度
                if self.original_image.mode not in ('RGBA', 'LA'):
                    self.original_image = self.original_image.convert('RGBA')
                self.edited_image = self.original_image.copy()
                self.scale_factor = 1.0
                self.reset_adjustment_sliders()
                self.display_image()
                self.add_log(f"打开图片: {os.path.basename(file_path)}")
            except Exception as e:
                messagebox.showerror("错误", f"无法打开图片: {str(e)}")
                self.add_log(f"打开图片失败: {str(e)}")

    def save_image(self):
        """保存图片（默认格式）"""
        if self.image_path and self.edited_image:
            try:
                # 保存时转换回原始模式（去除alpha通道如果原图没有）
                original_mode = Image.open(self.image_path).mode
                if original_mode not in ('RGBA', 'LA'):
                    saved_image = self.edited_image.convert(original_mode)
                else:
                    saved_image = self.edited_image

                saved_image.save(self.image_path)
                self.add_log(f"保存图片: {os.path.basename(self.image_path)}")
                messagebox.showinfo("成功", "图片已保存")
            except Exception as e:
                messagebox.showerror("错误", f"保存图片失败: {str(e)}")
                self.add_log(f"保存图片失败: {str(e)}")
        else:
            self.save_image_as()

    def save_image_as(self):
        """另存为其他格式"""
        if self.edited_image:
            file_extensions = [
                ("PNG文件", "*.png"),
                ("JPEG文件", "*.jpg"),
                ("BMP文件", "*.bmp"),
                ("ICO文件", "*.ico")
            ]

            file_path = filedialog.asksaveasfilename(
                defaultextension=".png",
                filetypes=file_extensions
            )

            if file_path:
                try:
                    # 根据扩展名确定格式
                    ext = os.path.splitext(file_path)[1].lower()
                    format_map = {
                        '.png': 'PNG',
                        '.jpg': 'JPEG',
                        '.jpeg': 'JPEG',
                        '.bmp': 'BMP',
                        '.ico': 'ICO'
                    }

                    img_format = format_map.get(ext, 'PNG')

                    # 对于JPEG等不支持alpha通道的格式，转换为RGB
                    if img_format in ['JPEG', 'BMP']:
                        saved_image = self.edited_image.convert('RGB')
                    else:
                        saved_image = self.edited_image

                    saved_image.save(file_path, format=img_format)
                    self.image_path = file_path
                    self.add_log(f"另存图片为: {os.path.basename(file_path)}")
                    messagebox.showinfo("成功", "图片已保存")
                except Exception as e:
                    messagebox.showerror("错误", f"保存图片失败: {str(e)}")
                    self.add_log(f"保存图片失败: {str(e)}")

    def reset_image(self):
        """重置图片到原始状态"""
        if self.original_image:
            self.edited_image = self.original_image.copy()
            self.scale_factor = 1.0
            self.reset_adjustment_sliders()
            self.display_image()
            self.add_log("图片已重置为原始状态")
        else:
            messagebox.showinfo("提示", "请先打开一张图片")

    def reset_adjustment_sliders(self):
        """重置调整滑块到默认值"""
        self.exposure_scale.set(1.0)
        self.alpha_scale.set(1.0)
        self.contrast_scale.set(1.0)
        self.saturation_scale.set(1.0)
        self.width_scale.set(2)

        self.exposure_label.config(text="1.00")
        self.alpha_label.config(text="1.00")
        self.contrast_label.config(text="1.00")
        self.saturation_label.config(text="1.00")

        self.drawing_color = "red"
        self.line_width = 2

    def display_image(self):
        """在画布上显示图片"""
        if self.edited_image:
            # 缩放图片用于显示
            width, height = self.edited_image.size
            new_width = int(width * self.scale_factor)
            new_height = int(height * self.scale_factor)
            self.displayed_image = self.edited_image.resize((new_width, new_height), Image.Resampling.LANCZOS)

            # 转换为Tkinter可用的格式
            self.tk_image = ImageTk.PhotoImage(image=self.displayed_image)

            # 清除画布并显示新图片
            self.canvas.delete("all")
            self.canvas.create_image(0, 0, anchor=tk.NW, image=self.tk_image)

            # 更新画布滚动区域
            self.canvas.config(scrollregion=self.canvas.bbox("all"))

    def zoom_image(self, factor):
        """缩放图片"""
        if self.edited_image:
            self.scale_factor *= factor
            # 限制缩放范围
            self.scale_factor = max(0.1, min(self.scale_factor, 5.0))
            self.display_image()
            self.add_log(f"图片缩放: {self.scale_factor:.2f}x")
        else:
            messagebox.showinfo("提示", "请先打开一张图片")

    def adjust_exposure(self, value):
        """调整图片曝光"""
        if self.edited_image and self.original_image:
            try:
                value = float(value)
                self.exposure_label.config(text=f"{value:.2f}")
                enhancer = ImageEnhance.Brightness(self.original_image)
                self.edited_image = enhancer.enhance(value)
                # 保持透明度设置
                self.apply_alpha(self.alpha_scale.get())
                self.display_image()
                self.add_log(f"调整曝光: {value:.2f}")
            except Exception as e:
                self.add_log(f"调整曝光失败: {str(e)}")

    def adjust_alpha(self, value):
        """调整图片透明度"""
        if self.edited_image:
            try:
                value = float(value)
                self.alpha_label.config(text=f"{value:.2f}")
                # 创建一个带有透明度的副本
                alpha = self.edited_image.split()[3]
                alpha = alpha.point(lambda p: p * value)
                self.edited_image.putalpha(alpha)
                self.display_image()
                self.add_log(f"调整透明度: {value:.2f}")
            except Exception as e:
                self.add_log(f"调整透明度失败: {str(e)}")

    def adjust_contrast(self, value):
        """调整图片对比度"""
        if self.edited_image and self.original_image:
            try:
                value = float(value)
                self.contrast_label.config(text=f"{value:.2f}")
                enhancer = ImageEnhance.Contrast(self.original_image)
                self.edited_image = enhancer.enhance(value)
                # 保持透明度设置
                self.apply_alpha(self.alpha_scale.get())
                self.display_image()
                self.add_log(f"调整对比度: {value:.2f}")
            except Exception as e:
                self.add_log(f"调整对比度失败: {str(e)}")

    def adjust_saturation(self, value):
        """调整图片饱和度"""
        if self.edited_image and self.original_image:
            try:
                value = float(value)
                self.saturation_label.config(text=f"{value:.2f}")
                enhancer = ImageEnhance.Color(self.original_image)
                self.edited_image = enhancer.enhance(value)
                # 保持透明度设置
                self.apply_alpha(self.alpha_scale.get())
                self.display_image()
                self.add_log(f"调整饱和度: {value:.2f}")
            except Exception as e:
                self.add_log(f"调整饱和度失败: {str(e)}")

    def apply_alpha(self, value):
        """应用透明度设置（用于其他调整后保持透明度）"""
        if self.edited_image:
            alpha = self.edited_image.split()[3]
            alpha = alpha.point(lambda p: p * value)
            self.edited_image.putalpha(alpha)

    def set_drawing_tool(self, tool):
        """设置当前绘图工具"""
        self.drawing_tool = tool
        tool_name = tool if tool else "选择"
        self.add_log(f"选择绘图工具: {tool_name}")

    def set_drawing_color(self, color):
        """设置绘图颜色"""
        self.drawing_color = color
        self.add_log(f"设置绘图颜色: {color}")

    def set_line_width(self, value):
        """设置线条宽度"""
        self.line_width = int(float(value))
        self.add_log(f"设置线条宽度: {self.line_width}")

    def on_mouse_down(self, event):
        """鼠标按下事件处理"""
        if self.drawing_tool and self.edited_image:
            self.start_x = event.x / self.scale_factor
            self.start_y = event.y / self.scale_factor

    def on_mouse_drag(self, event):
        """鼠标拖动事件处理"""
        if self.drawing_tool and self.start_x is not None and self.start_y is not None:
            # 清除临时绘制
            if self.temp_drawing:
                self.canvas.delete(self.temp_drawing)

            # 绘制临时图形
            x1, y1 = self.start_x * self.scale_factor, self.start_y * self.scale_factor
            x2, y2 = event.x, event.y

            if self.drawing_tool == "line":
                self.temp_drawing = self.canvas.create_line(x1, y1, x2, y2, width=self.line_width,
                                                            fill=self.drawing_color)
            elif self.drawing_tool == "rectangle":
                self.temp_drawing = self.canvas.create_rectangle(x1, y1, x2, y2, outline=self.drawing_color,
                                                                 width=self.line_width)
            elif self.drawing_tool == "oval":
                self.temp_drawing = self.canvas.create_oval(x1, y1, x2, y2, outline=self.drawing_color,
                                                            width=self.line_width)
            elif self.drawing_tool == "triangle":
                # 三角形，以起点为一个顶点，终点为对角
                self.temp_drawing = self.canvas.create_polygon(
                    x1, y1, x2, y2, (x1 + x2) / 2, y1,
                    outline=self.drawing_color, width=self.line_width, fill=""
                )

    def on_mouse_up(self, event):
        """鼠标释放事件处理"""
        if self.drawing_tool and self.start_x is not None and self.start_y is not None:
            # 获取实际图片坐标（考虑缩放）
            x1, y1 = self.start_x, self.start_y
            x2, y2 = event.x / self.scale_factor, event.y / self.scale_factor

            # 在实际图片上绘制
            draw = ImageDraw.Draw(self.edited_image)

            if self.drawing_tool == "line":
                draw.line([x1, y1, x2, y2], fill=self.drawing_color, width=self.line_width)
                self.add_log(f"绘制直线: ({int(x1)},{int(y1)}) 到 ({int(x2)},{int(y2)})")
            elif self.drawing_tool == "rectangle":
                draw.rectangle([x1, y1, x2, y2], outline=self.drawing_color, width=self.line_width)
                self.add_log(f"绘制矩形: ({int(x1)},{int(y1)}) 到 ({int(x2)},{int(y2)})")
            elif self.drawing_tool == "oval":
                draw.ellipse([x1, y1, x2, y2], outline=self.drawing_color, width=self.line_width)
                self.add_log(f"绘制圆形: ({int(x1)},{int(y1)}) 到 ({int(x2)},{int(y2)})")
            elif self.drawing_tool == "triangle":
                draw.polygon([x1, y1, x2, y2, (x1 + x2) / 2, y1], outline=self.drawing_color, width=self.line_width)
                self.add_log(f"绘制三角形: 三个顶点坐标")

            # 清除临时绘制并更新显示
            if self.temp_drawing:
                self.canvas.delete(self.temp_drawing)
                self.temp_drawing = None

            self.start_x = None
            self.start_y = None
            self.display_image()

    def crop_image(self):
        """裁剪图片"""
        if self.edited_image:
            # 创建裁剪对话框
            crop_dialog = ttkb.Toplevel(self)
            crop_dialog.title("裁剪图片")
            crop_dialog.geometry("300x200")
            crop_dialog.transient(self)
            crop_dialog.grab_set()

            # 居中显示
            crop_dialog.update_idletasks()
            width = crop_dialog.winfo_width()
            height = crop_dialog.winfo_height()
            x = (self.winfo_width() // 2) - (width // 2) + self.winfo_x()
            y = (self.winfo_height() // 2) - (height // 2) + self.winfo_y()
            crop_dialog.geometry(f"+{x}+{y}")

            # 裁剪参数
            ttkb.Label(crop_dialog, text="裁剪区域 (百分比):").pack(pady=10)

            frame = ttkb.Frame(crop_dialog)
            frame.pack(fill=X, padx=20, pady=5)

            ttkb.Label(frame, text="左:").grid(row=0, column=0, padx=5)
            left_entry = ttkb.Entry(frame, width=5)
            left_entry.grid(row=0, column=1, padx=5)
            left_entry.insert(0, "10")

            ttkb.Label(frame, text="上:").grid(row=0, column=2, padx=5)
            top_entry = ttkb.Entry(frame, width=5)
            top_entry.grid(row=0, column=3, padx=5)
            top_entry.insert(0, "10")

            frame2 = ttkb.Frame(crop_dialog)
            frame2.pack(fill=X, padx=20, pady=5)

            ttkb.Label(frame2, text="右:").grid(row=0, column=0, padx=5)
            right_entry = ttkb.Entry(frame2, width=5)
            right_entry.grid(row=0, column=1, padx=5)
            right_entry.insert(0, "90")

            ttkb.Label(frame2, text="下:").grid(row=0, column=2, padx=5)
            bottom_entry = ttkb.Entry(frame2, width=5)
            bottom_entry.grid(row=0, column=3, padx=5)
            bottom_entry.insert(0, "90")

            # 确认按钮
            def apply_crop():
                try:
                    left = int(left_entry.get())
                    top = int(top_entry.get())
                    right = int(right_entry.get())
                    bottom = int(bottom_entry.get())

                    if not (0 <= left < right <= 100 and 0 <= top < bottom <= 100):
                        messagebox.showerror("错误", "请输入有效的百分比值")
                        return

                    width, height = self.edited_image.size
                    left_pixel = int(width * left / 100)
                    top_pixel = int(height * top / 100)
                    right_pixel = int(width * right / 100)
                    bottom_pixel = int(height * bottom / 100)

                    self.edited_image = self.edited_image.crop((left_pixel, top_pixel, right_pixel, bottom_pixel))
                    self.original_image = self.edited_image.copy()  # 更新原始图像以便后续调整
                    self.display_image()
                    self.add_log(f"裁剪图片: 从 ({left}%,{top}%) 到 ({right}%,{bottom}%)")
                    crop_dialog.destroy()
                except ValueError:
                    messagebox.showerror("错误", "请输入有效的数字")

            btn_frame = ttkb.Frame(crop_dialog)
            btn_frame.pack(fill=X, padx=20, pady=20)

            ttkb.Button(btn_frame, text="确认", command=apply_crop, bootstyle=SUCCESS).pack(side=LEFT, padx=5, fill=X,
                                                                                            expand=True)
            ttkb.Button(btn_frame, text="取消", command=crop_dialog.destroy, bootstyle=DANGER).pack(side=LEFT, padx=5,
                                                                                                    fill=X, expand=True)
        else:
            messagebox.showinfo("提示", "请先打开一张图片")

    def add_log(self, message):
        """添加日志信息"""
        timestamp = datetime.datetime.now().strftime("%H:%M:%S")
        log_entry = f"[{timestamp}] {message}\n"

        self.log_text.config(state=NORMAL)
        self.log_text.insert(END, log_entry)
        self.log_text.see(END)  # 滚动到最后
        self.log_text.config(state=DISABLED)

    def create_widgets(self):
        pass
